﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once

#include "NdbObjectCloneable.h"
#include "NdbObjectSchematic.h"
#include "NdbDataInterface.h"

namespace gcmp
{
    template<class T, class Enable = void>
    class ReportElementIdHelper
    {
    public:
        static void ReportElementId(const T& value, std::set<ElementId>* /*pElementIds*/,
            std::unordered_map<ElementId, std::vector<std::wstring>, ElementIdHash>* pPaths = nullptr
            , std::vector<std::wstring>* pCurrentPath = nullptr)
        {
        }
    };

    template<>
    class ReportElementIdHelper<ElementId>
    {
    public:
        static void ReportElementId(const ElementId& value, std::set<ElementId>* pElementIds,
            std::unordered_map<ElementId, std::vector<std::wstring>, ElementIdHash>* pPaths = nullptr
            , std::vector<std::wstring>* pCurrentPath = nullptr)
        {
            DBG_WARN_AND_RETURN_VOID_UNLESS(pElementIds, L"pElementIds不应该为空", L"GMEP", L"2016/10/14");
            pElementIds->insert(value);
            if(pPaths && pCurrentPath)
            {
                pPaths->insert(std::pair<ElementId, std::vector<std::wstring>>(value, *pCurrentPath));
            }
        }
    };

    template<class T>
    class ReportElementIdHelper<gcmp::OwnerPtr<T>>
    {
    public:
        static void ReportElementId(const gcmp::OwnerPtr<T>& value, std::set<ElementId>* pElementIds,
            std::unordered_map<ElementId, std::vector<std::wstring>, ElementIdHash>* pPaths = nullptr
            , std::vector<std::wstring>* pCurrentPath = nullptr)
        {
            DBG_WARN_AND_RETURN_VOID_UNLESS(pElementIds, L"pElementIds不应该为空", L"GMEP", L"2016/10/14");
            if (value != nullptr)
            {
                ReportElementIdHelper<T>::ReportElementId(*(value.get()), pElementIds, pPaths, pCurrentPath);
            }
        }
    };

    template<class T>
    class ReportElementIdHelper<T, typename std::enable_if<std::is_base_of<NdbObjectCloneable, T>::value>::type>
    {
    public:
        static void ReportElementId(const NdbObjectCloneable& value, std::set<ElementId>* pElementIds,
            std::unordered_map<ElementId, std::vector<std::wstring>, ElementIdHash>* pPaths = nullptr
            , std::vector<std::wstring>* pCurrentPath = nullptr)
        {
            DBG_WARN_AND_RETURN_VOID_UNLESS(pElementIds, L"pElementIds不应该为空", L"GMEP", L"2016/10/14");
            value.ReportElementIds(pElementIds);
        }
    };

    template<class T>
    class ReportElementIdHelper<T, typename std::enable_if<std::is_base_of<NdbObjectSchematic, T>::value>::type>
    {
    public:
        static void ReportElementId(const T& value, std::set<ElementId>* pElementIds,
            std::unordered_map<ElementId, std::vector<std::wstring>, ElementIdHash>* pPaths = nullptr
            , std::vector<std::wstring>* pCurrentPath = nullptr)
        {
            DBG_WARN_AND_RETURN_VOID_UNLESS(pElementIds, L"pElementIds不应该为空", L"GMEP", L"2016/10/14");
            gcmp::NdbDataInterface::GetReferencedElementIds(&value, pElementIds, pPaths, pCurrentPath);
        }
    };

    template<class T>
    class ReportElementIdHelper<T, typename std::enable_if<std::is_base_of<IDbObject, T>::value && !std::is_base_of<NdbObjectSchematic, T>::value && !std::is_base_of<NdbObjectCloneable, T>::value>::type>
    {
    public:
        static void ReportElementId(const T& value, std::set<ElementId>* pElementIds,
            std::unordered_map<ElementId, std::vector<std::wstring>, ElementIdHash>* pPaths = nullptr
            , std::vector<std::wstring>* pCurrentPath = nullptr)
        {
            DBG_WARN_AND_RETURN_VOID_UNLESS(pElementIds, L"pElementIds不应该为空", L"GMEP", L"2016/10/14");
            const IDbObject * pIDbObject = &value;
            if (pIDbObject)
            {
                if (const NdbObjectSchematic * pNdbObjectSchematic = thread_safe_quick_cast<NdbObjectSchematic>(pIDbObject))
                {
                    gcmp::NdbDataInterface::GetReferencedElementIds(pNdbObjectSchematic, pElementIds, pPaths, pCurrentPath);
                }
                else if (const NdbObjectCloneable* pNdbObjectCloneable = thread_safe_quick_cast<NdbObjectCloneable>(pIDbObject))
                {
                    pNdbObjectCloneable->ReportElementIds(pElementIds);
                }
                else
                {
                    // 不要求通过Ndb去报告纯IDbObject内部的ElementId
                }
            }
        }
    };
}
